#include "EnvironmentShader.h"
#include "RayTraceSystem.h"
#include "TextureData.h"

namespace RayTracePro
{
	using namespace GxLibBasic;
	using namespace GxLibMath;

	EnvironmentShader::EnvironmentShader(RayTraceSystem * system, const String & fileName)
	{
		UBias = VBias = 0.0f;
		texture = system->LoadTexture(fileName.GetStrPtr());
		this->system = system;
	}

	EnvironmentShader::~EnvironmentShader()
	{
		system->FreeTexture(texture);
	}

	void EnvironmentShader::Shade(Vec4 & result, const Vec3 & dir, const Vec3 & dDdx, const Vec3 & dDdy)
	{
		float u,v;
		CartesianToSphere(dir, u, v);
		u += UBias;  v += VBias;
		u -= floor(u); v -= floor(v);
		if (system->TextureFilter == RayTraceSystem::TextureFilterLinear)
		{
			SampleTextureLevel(&result, texture, 0, Vec2(u, v));
			return;
		}	
		float dudx, dvdx, dudy, dvdy;
		Vec3 dbx, dby;
		Vec3::Add(dbx, dir, dDdx);
		Vec3::Add(dby, dir, dDdy);
		Vec3::Normalize(dbx, dbx);
		Vec3::Normalize(dby, dby);
		CartesianToSphere(dbx, dudx, dvdx);
		CartesianToSphere(dby, dudy, dvdy);
		dudx -= u; dvdx -= v;
		dudy -= u; dvdy -= v;
		dudx = abs(dudx);
		dudy = abs(dudy);
		dvdx = abs(dvdx);
		dvdy = abs(dvdy);
		if (dudx > 0.5f) dudx = 1.0f - dudx;
		if (dudy > 0.5f) dudy = 1.0f - dudy;
		if (dvdx > 0.5f) dvdx = 1.0f - dvdx;
		if (dvdy > 0.5f) dvdy = 1.0f - dvdy;
		if (system->TextureFilter == RayTraceSystem::TextureFilterTrilinear)
			TrilinearSampling(&result, texture, max(abs(dudx), abs(dvdy)), max(abs(dvdx), abs(dudy)), Vec2(u, v));
		else
			AnisotropicSampling(&result, texture, system->TextureFilterAnisotropicRate, dudx, dvdx, dudy, dvdy, Vec2(u, v));

	}
}